Skip to content

Copilot: surface AI credit usage for token-based-billing seats - #2647

Open
KSEGIT wants to merge 11 commits into
steipete:mainfrom
KSEGIT:copilot-ai-credits
Open

Copilot: surface AI credit usage for token-based-billing seats#2647
KSEGIT wants to merge 11 commits into
steipete:mainfrom
KSEGIT:copilot-ai-credits

Conversation

@KSEGIT

@KSEGIT KSEGIT commented Aug 4, 2026

Copy link
Copy Markdown

Closes #2593.

Rebased 2026-08-08. Since #2613 landed stage 1 (decoding credits_used and rendering it through the shared provider-detail contract), this branch was rebuilt on current main and now carries only the remainder: the opt-in organization lane, user-entered credit entitlements (now per GitHub account), and the progress-bar display beyond stage 1. Seat credits flow through main's shared detail rows — no parallel credit state.

The problem

On a Copilot Business seat with token_based_billing: true, GET /copilot_internal/user reports every quota snapshot as unlimited: true, entitlement: 0, remaining: 0, percent_remaining: 100. The #1258 guards correctly drop those so no misleading "0% used" bar appears — but the result is a Copilot card showing only the plan label and no usage at all.

Real consumption is available, in two places CodexBar didn't read:

  1. credits_used, already present on each quota snapshot in the response CodexBar already fetches (landed in Decode Copilot credits_used for token-billed seats (#2593) #2613).
  2. GET /organizations/{org}/settings/billing/ai_credit/usage — org-wide, per-model (this PR).

GitHub publishes no credit entitlement anywhere

This is the finding that shaped the design. I probed all 8 documented billing endpoints plus budgets, cost-centers, included_credits, ai_credit/entitlement, copilot/metrics and usage/summary. None expose the included-credit ceiling — the "6,000" that the org billing page displays. discountQuantity reveals only what included credits absorbed, so the ceiling is observable only once exceeded.

It is derivable as seats × per-seat allowance, but the per-seat figure is currently a promotional 3,000 against a standard 1,900 — a hardcoded table would silently produce a wrong bar when the promo ends. So the denominator is user-entered and never inferred. A lane with no entitlement renders a text row, never a bar with a fabricated ceiling.

If you know of an endpoint I missed, that would simplify this considerably.

What this adds

Seat credit bar (builds on #2613). Extends the shared provider-detail row contract with an optional row id and progress ratio (ProviderDetailSection.Row), so the existing "Credits used" row becomes a "31 / 3000" bar when a seat entitlement is set, and stays plain text otherwise. Created only when it carries real signal (token-billed / unlimited quota / credits > 0 / entitlement set), so metered accounts reporting credits_used: 0 don't gain a permanent empty row. No guard line in CopilotUsageFetcher.swift is modified — the #1258 guard block is byte-identical to main.

Org lane (opt-in, off by default). GET /organizations/{org}/settings/billing/ai_credit/usage (the documented path), org read from organization_login_list.first, summing usageItems[].grossQuantity filtered to credit unit types — "credits" per the organization-report docs, "ai-credits" per the user-level docs and live org responses; both are accepted, unrelated unit types are rejected (a response with no credit items returns nil, never a fabricated 0). Strictly best-effort, shaped like the existing addBudgetWindowsIfNeeded: any failure returns the snapshot untouched. The device flow still requests only read:user, so rejection is the expected common case, not an error — it logs a warning rather than failing silently.

On my account the org endpoint returns 31.13 + 49.97 = 81.10, matching the billing page's numerator exactly.

Per-account entitlements. Seat and org allowances are stored on the selected ProviderTokenAccount (following the z.ai per-account fields precedent), resolved in copilotSettingsSnapshot with the existing global UserDefaults values as fallback — so existing single-account setups keep working unchanged, and two Copilot accounts with different allowances each get the right denominator. The settings fields write to the selected account when one exists.

Which surfaces this covers

Worth being explicit, since it's a menu bar app:

Surface Covered
Menu card (provider card rows) ✅ yes
Menu bar icon ❌ no
Widget ❌ no
codexbar usage CLI ❌ no

Credits are detail rows, not a RateWindow, because a lane with no user-entered entitlement has no percentage to show. MenuBarLayout, IconRemainingResolver and the widget all build from primary/secondary/tertiary/extraRateWindows, so they see nothing.

The consequence: a Business token-billing user still gets an empty menu bar icon and must open the menu to see credits. I'd rather state that than have you find it.

Making the icon work needs a decision I didn't want to make unilaterally: publishing credits as a NamedRateWindow when an entitlement exists would light up the icon, widget and the existing "menu bar secondary metric" picker for free, but Copilot's extra windows are gated behind copilotBudgetExtrasEnabled in the card renderer, so it risks either double-rendering the row or coupling credits to an unrelated setting. Happy to do it in this PR if you'll say which shape you want.

Testing

  • 191 focused tests across the 10 touched suites green (fetcher, parser, settings, wiring, menu-card model, detail sections, persistence round-trip).
  • make check — 0 violations across 1,811 files.
  • make test — full suite green except MiniMaxMenuCardBillingTests, which fails identically on a clean origin/main checkout on this machine (locale-dependent number grouping, "1.234" vs "1,234"); unrelated to this PR.
  • All new tests use ProviderHTTPTransportStub or the existing URLProtocol stub. No live network, no Keychain access, per AGENTS.md.

Regression coverage worth calling out: a test asserts the #1258 behaviour still holds — a Business token-billing payload yields credits and primary == nil, secondary == nil. New per-account tests cover: account override wins over the global fallback, fallback when the account has no value, two accounts producing different snapshot entitlements, and a Codable round-trip through the config store (including legacy JSON without the new keys).

Known limitations

  • Localization: L("AI credits"), L("Org credits"), L("credits used") have no Localizable.strings entries. Scripts/check-app-locales.mjs enforces all 23 catalogs together, so a partial addition fails make check — left out deliberately rather than done badly. Happy to add all 23 here if you'd prefer.
  • Org selection: organization_login_list.first wins when a user belongs to several orgs. The row title names the org so it isn't ambiguous, but there's no picker.
  • Account field semantics: an account without an override displays the global fallback value; saving the field unchanged freezes that value onto the account. Clearing the field removes the override and re-displays the fallback.
  • Entitlement lives on the fetch path rather than being applied at render time. Consequence: the bar appears only after a successful refresh, and clearing the field leaves the cached denominator until one succeeds.
  • No pace/projection on credit rows yet, though resetsAt is available and a monthly credit budget is a good fit for it (cf. Show ahead/behind pace for all providers and in the menu bar #807, Add Projections to Copilot Tracker #2166).

Commits

9 focused commits, each with its own tests, left unsquashed so they can be reviewed in sequence. Squash on merge if you'd rather.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aaeb632f41

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

else { return nil }
return CopilotDeviceFlow.makeRequestURL(
host: CopilotUsageFetcher.apiHost(enterpriseHost: enterpriseHost),
path: "/orgs/\(encoded)/settings/billing/ai_credit/usage")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the documented organizations billing path

For the organization AI-credit flow, GitHub's REST docs list this endpoint as GET /organizations/{org}/settings/billing/ai_credit/usage, not /orgs/{org}/... (checked https://docs.github.com/en/rest/billing/usage#get-billing-ai-credit-usage-report-for-an-organization). With the current path, authorized org admins receive a 404 and fetchCreditsUsed returns nil, so the new organization credits row never appears.

Useful? React with 👍 / 👎.

return 0
}

let creditItems = report.usageItems.filter { $0.unitType == "ai-credits" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept the org AI-credit unit type

For organization AI-credit reports, GitHub's example response uses unitType: "credits", while "ai-credits" is shown for user-level reports (checked https://docs.github.com/en/rest/billing/usage#get-billing-ai-credit-usage-report-for-an-organization). After the path is corrected, real org responses will fall into the “none matched” branch here and return nil, so organization usage still will not render unless this accepts the org unit type.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Aug 4, 2026
@clawsweeper

clawsweeper Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed August 12, 2026, 8:09 AM ET / 12:09 UTC.

ClawSweeper review

What this changes

This PR adds a per-Copilot-account AI-credit allowance that renders existing seat credit usage as a menu-card progress bar and updates the visible cached row when the allowance changes.

Merge readiness

Blocked until stronger real behavior proof is added - 4 items remain

Keep open: the seat-credit UI is a useful remaining feature beyond the shipped credit counter, but the current head still lacks real after-fix proof for its cached text-to-bar transition.

Priority: P2
Reviewed head: 766101c2d0c0525b75640df4c86f95e9a4678d48

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) The implementation and focused coverage appear solid, but current-head real behavior proof is still required before merge.
Proof confidence 🦪 silver shellfish (2/6) Needs stronger real behavior proof before merge: A prepared screenshot convincingly shows the earlier live credit bar, but it predates current head's cached text-to-bar repair and does not demonstrate that changed behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Needs proof Needs stronger real behavior proof before merge: A prepared screenshot convincingly shows the earlier live credit bar, but it predates current head's cached text-to-bar repair and does not demonstrate that changed behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 5 items Current main baseline: Current main already retains Copilot credits as a plain provider-detail row while keeping token-billed placeholder quotas out of percentage windows; this PR extends that row into an opt-in ratio.
Shipped stage-one provenance: The existing credits counter was introduced by the merged stage-one change and is contained in the v0.48.0 tag; the remaining menu-card bar is not on current main.
Live proof is older than the current repair: The prepared screenshot visibly shows a live 1188 / 3000 Copilot bar, but its associated comment identifies head b7406fb; current head 766101c adds the cached text-to-bar repair and the author said its proof was still forthcoming.
Findings None None.
Security None None.

How this fits together

CodexBar fetches Copilot quota data, turns it into provider-detail rows in a usage snapshot, and renders those rows in the menu card. This change supplies a user-entered seat allowance so a known credit counter can be shown as a ratio without inventing a limit.

flowchart LR
A[Copilot account] --> B[GitHub usage response]
C[Seat allowance setting] --> D[Credit row builder]
B --> D
D --> E[Cached usage snapshot]
E --> F[Menu card text or progress bar]
Loading

Before merge

  • Add real behavior proof - Needs stronger real behavior proof before merge: A prepared screenshot convincingly shows the earlier live credit bar, but it predates current head's cached text-to-bar repair and does not demonstrate that changed behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Resolve merge risk (P1) - The branch adds persisted per-account data and shared Codable detail-row fields, so compatibility should be refreshed against current main before merge.
  • Resolve merge risk (P1) - The only inspected live screenshot predates the current-head cached text-to-bar repair; merging without a current-head transition run leaves the changed offline/cache behavior unproven.
  • Complete next step (P2) - A contributor-provided current-head run is required; automated repair cannot establish real behavior on the contributor's Copilot Business seat.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Diff scope 27 files changed; +1,186 / -39 lines The feature crosses the shared detail model, persisted token-account settings, fetch path, cache handling, UI, and tests.

Merge-risk options

Maintainer options:

  1. Refresh compatibility and proof (recommended)
    Rebase or otherwise validate the current merge result, then add redacted current-head evidence for the cached allowance transition before merge.

Technical review

Best possible solution:

Rebase or refresh against current main, then provide a redacted current-head run that shows a real Copilot credit row changing from text to bar when an allowance is entered and back to text when cleared.

Do we have a high-confidence way to reproduce the issue?

Yes—source and the supplied fixture/live payload establish the path: a token-billed Copilot response with credits_used plus a configured seat allowance produces the detail-row ratio. A real current-head account run is still needed to prove the cache-transition behavior.

Is this the best way to solve the issue?

Yes in design: an opt-in, per-account denominator avoids fabricating GitHub credit limits while preserving the existing no-fake-percentage guard. It is not yet merge-ready without current-head proof of the cached transition.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a90dfed5c264.

Labels

Label changes:

  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🦪 silver shellfish, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded user-facing Copilot usage improvement with no demonstrated urgent outage or data-loss impact.
  • merge-risk: 🚨 compatibility: The PR extends persisted token-account data and the shared Codable provider-detail row contract used across existing snapshots and UI surfaces.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: A prepared screenshot convincingly shows the earlier live credit bar, but it predates current head's cached text-to-bar repair and does not demonstrate that changed behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. A prepared screenshot convincingly shows the earlier live credit bar, but it predates current head's cached text-to-bar repair and does not demonstrate that changed behavior.

Evidence

What I checked:

  • Current main baseline: Current main already retains Copilot credits as a plain provider-detail row while keeping token-billed placeholder quotas out of percentage windows; this PR extends that row into an opt-in ratio. (Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift:74, a90dfed5c264)
  • Shipped stage-one provenance: The existing credits counter was introduced by the merged stage-one change and is contained in the v0.48.0 tag; the remaining menu-card bar is not on current main. (Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift:74, 2d76cd9e9fca)
  • Live proof is older than the current repair: The prepared screenshot visibly shows a live 1188 / 3000 Copilot bar, but its associated comment identifies head b7406fb; current head 766101c adds the cached text-to-bar repair and the author said its proof was still forthcoming. (766101c2d0c0)
  • Shared-detail ownership: The current declarative provider-detail model was introduced by the recent shared refactor, making its compatibility the relevant review surface for the added optional row data. (Sources/CodexBarCore/ProviderDetailSection.swift:7, 8314a74e8613)
  • Inspection limitation: The local checkout could inspect current main, but could not materialize the PR-head Git object because its promisor remote could not resolve github.com; branch-specific assessment therefore uses the supplied PR diff and discussion evidence. (766101c2d0c0)

Likely related people:

  • steipete: Authored the current shared provider-detail refactor and explicitly asked for this follow-on work after stage one landed. (role: recent shared-detail refactor author and repository owner; confidence: high; commits: 8314a74e8613; files: Sources/CodexBarCore/ProviderDetailSection.swift, Sources/CodexBar/ProviderDetailSectionsContent.swift)
  • Yuxin-Qiao: Authored the merged stage-one credits_used implementation that this PR extends. (role: introduced the current Copilot credit counter; confidence: high; commits: 2d76cd9e9fca; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift, Sources/CodexBarCore/CopilotUsageModels.swift)
  • Zihao-Qi: Authored the unlimited-quota guard whose no-fabricated-percentage behavior this PR preserves. (role: adjacent Copilot quota-guard contributor; confidence: medium; commits: 6d71af30b84d; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Add a redacted current-head run showing text-only credits becoming a bar after entering an allowance, including the offline or failed-refresh path.
  • Refresh the branch against current main and rerun the focused Copilot and cache-state coverage.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (26 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-09T07:16:30.325Z sha b7406fb :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-09T08:32:39.020Z sha b7406fb :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T11:00:08.310Z sha b7406fb :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T14:17:20.254Z sha b7406fb :: found issues before merge. :: [P2] Update cached credit rows when entitlements change
  • reviewed 2026-08-09T19:21:46.140Z sha 14599df :: needs changes before merge. :: [P2] Preserve a numerator for text-only credit rows
  • reviewed 2026-08-09T19:49:53.189Z sha 14599df :: needs changes before merge. :: [P2] Rebuild text-only rows when an entitlement is entered
  • reviewed 2026-08-09T22:02:41.600Z sha 14599df :: needs real behavior proof before merge. :: [P2] Preserve numeric usage for text-only credit rows
  • reviewed 2026-08-10T20:46:31.316Z sha 766101c :: needs real behavior proof before merge. :: none

@steipete

steipete commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Thanks for this, and for the excellent original report in #2593 — you found both the credits_used field and the org-billing endpoint. Heads-up on sequencing: #2613 is green and staged to land stage 1 of this (decoding credits_used from the already-fetched copilot_internal/user response). Rather than closing anything, the ask is: once #2613 merges, could you rebase this PR on top so it carries just the remainder (the org billing endpoint and the UI surface beyond stage 1)? Your issue and this PR shaped the direction here, so we'd love to land the rest with your name on it.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 5, 2026
@KSEGIT

KSEGIT commented Aug 7, 2026

Copy link
Copy Markdown
Author

Re status: 📣 needs proof — here's what I can evidence, and what I can't.

The upstream data is real, not inferred

Live from a Copilot Business seat (redacted), via the endpoint CodexBar already calls:

"quota_snapshots": {
  "premium_interactions": { "unlimited": true, "entitlement": 0, "remaining": 0,
                            "percent_remaining": 100.0, "credits_used": 31,
                            "token_based_billing": true, "overage_permitted": true },
  "chat":        { "unlimited": true, "entitlement": 0, "credits_used": 0 },
  "completions": { "unlimited": true, "entitlement": 0, "credits_used": 0 }
},
"organization_login_list": ["<ORG>"],
"copilot_plan": "business", "token_based_billing": true,
"quota_reset_date": "2026-09-01"

Note credits_used: 0 on chat/completions — that's why the seat lane reads only premium_interactions rather than summing, and why lane creation is gated on real signal instead of on the field merely decoding.

And the org endpoint:

{ "usageItems": [
    { "product": "Copilot", "sku": "Copilot AI Credits",  "model": "Code Review model",
      "unitType": "ai-credits", "pricePerUnit": 0.01, "grossQuantity": 31.13 },
    { "product": "Copilot", "sku": "Copilot Cloud Agent", "model": "Coding Agent model",
      "unitType": "ai-credits", "pricePerUnit": 0.01, "grossQuantity": 49.97 } ] }

31.13 + 49.97 = 81.10, which matches the "81 / 6,000 AI credits" numerator on the org billing page exactly. That agreement is the strongest evidence I have that the org lane reads the right thing.

What the card actually renders

Asserted on exact strings through the real UsageMenuCardView.Model.make(...) path, not on internals:

Case Assertion Location
Entitlement set title == "AI credits", detailLeftText == "31 / 3000", statusText == nil (bar renders) CopilotMenuCardModelTests.swift:149-151
No entitlement statusText == "31 credits used" (text row, bar suppressed) :161
Org lane row id copilot-org-credits, title carries the org login :170
Org via real fetch path org?.creditsUsed == 81.1, org?.entitlement == 6000 CopilotBudgetWebFetcherTests.swift:516-518
Org call rejected (403) copilotCredits?.org == nil, seat lane survives :582
Toggle off endpoint never contacted (Issue.record on any request) :641

The org tests drive descriptor.fetchPlan.fetchOutcome, so they exercise the production strategy rather than a shortcut.

What I can't evidence yet

No screenshot. Producing one means building this branch, packaging it, and running it against a real Copilot Business account — which per AGENTS.md is exactly the kind of validation that can raise Keychain prompts, so I didn't do it unasked. Happy to if you want it.

Two of three surfaces are untouched. I've added a table to the PR description rather than leave it implied: the menu card shows credits; the menu bar icon, the widget, and codexbar usage do not. Credits are a new UsageSnapshot field rather than a RateWindow (a lane without a user-entered entitlement has no percentage), and those three surfaces all build from primary/secondary/tertiary/extraRateWindows.

So today a Business token-billing user still gets an empty icon and has to open the menu. I can wire the icon up in this PR — publishing credits as a NamedRateWindow when an entitlement exists would cover icon, widget and the existing secondary-metric picker at once — but Copilot's extra windows are gated behind copilotBudgetExtrasEnabled in the card renderer, so it needs a call on whether to reuse that gate, add a new one, or exclude these windows from the card path to avoid double-rendering. Tell me which and I'll do it.

Since the PR was opened

  • Swapped a private number formatter for UsageFormatter.creditsNumberString (bfe422a), so Copilot and Codex credit numbers no longer disagree on grouping in the same menu.
  • Documented the global-entitlement limitation for multi-account setups, and the org-selection behaviour, in the PR description.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 7, 2026
@clawsweeper

clawsweeper Bot commented Aug 8, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Aug 8, 2026
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

After-fix runtime proof — head b7406fb8, built from the branch, packaged and run locally 2026-08-09 against my live Copilot Business seat.

Menu card (live)

Copilot menu card: Credits used 1188 / 3000 with progress bar

  • CREDITS"Credits used — 1188 / 3000", reset 1 Sep at 01:00, progress bar at ~40% (1188/3000 = 39.6%). Numerator comes from the already-fetched copilot_internal/user response; the 3000 denominator is the per-account seat entitlement.
  • The bar only renders because an entitlement is set — without one this is a text row, per the no-fabricated-ceiling design.

Org lane trace (live)

log show on com.steipete.codexbar:providers during a refresh:

09:23:06 Error CodexBar: [providers] Copilot org credits unavailable (statusCode=404)

The best-effort degradation works exactly as designed: warning logged, card unaffected, no fabricated org row, seat lane intact.

A finding from the live run: the 404 is a scope issue, not a path issue

With a read:org token I get 200 from both /orgs/{org}/settings/billing/ai_credit/usage and /organizations/{org}/settings/billing/ai_credit/usage, for every org I belong to (verified via gh api). So both spellings route — and this PR uses the documented /organizations/ one.

The Copilot device flow requests only read:user, and GitHub hides org billing endpoints from such tokens behind 404 (the docs require org "Administration" read for fine-grained tokens; classic tokens need read:org plus admin membership). So as shipped, the org lane can only succeed for users whose token already carries org billing visibility — the device-flow token never will. Options: (a) ship as-is — opt-in lane, documented best-effort; (b) add read:org to the device-flow scope so the lane can actually light up for org admins, at the cost of a bigger scope ask on every Copilot sign-in. I stayed with (a) since (b) is a product call, but flagging it explicitly now that it's proven live rather than assumed.

@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 9, 2026
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@steipete Hi there, I think it is ready to merge :) Let me know if you want me to do anything more :)

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Aug 9, 2026
Remove the opt-in organization billing lane pending an approved
authorization model for org-wide billing reads with device-flow tokens.

Rewrite the cached seat credit row immediately when the entitlement
changes so a stale denominator or bar never survives a failed refresh.
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

Addressed the 2026-08-09 14:17 UTC review on head 14599df:

  • Org lane deferred (owner-decision item): removed the opt-in organization billing request, org entitlements, toggle, fetcher, and docs — this PR is now seat credits only, per the recommended option. Happy to bring the org lane back in a follow-up once an authorization model is approved.
  • Stale cached rows fixed (P2): changing or clearing the seat entitlement now rewrites the cached Credits used row synchronously in both the live snapshot and the last-known-reset baseline (numerator taken from the row's structured progress, never parsed from display text), so an offline/failed refresh can no longer leave a stale denominator or bar. Covered by 5 new UsageStoreCoverageTests cases including the stale-reset-baseline path.

make check clean (SwiftFormat + SwiftLint, 0 violations); focused Copilot/UsageStore suites green. Full make test: 68/69 groups pass — the one failure is a pre-existing locale-sensitive MiniMax billing assertion on main (unrelated files, untouched by this PR).

@clawsweeper

clawsweeper Bot commented Aug 9, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. proof: sufficient Contributor real behavior proof is sufficient. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 9, 2026
Text-only credit rows carried no structured usage, so entering an
entitlement during an offline or failed refresh left the cached row
without its bar. Stamp usageValue on the row at fetch time and use it
as the repair numerator.
@KSEGIT

KSEGIT commented Aug 10, 2026

Copy link
Copy Markdown
Author

Head 766101c addresses the P2 cached-state finding from the 22:02 UTC review:

  • Text-only Credits used rows now carry their numeric usage structurally (usageValue on the shared row contract, additive and Codable-backward-compatible), so entering an entitlement rebuilds the cached row into a bar immediately — no refresh required, offline included. Clearing restores the text-only row. Rows with no numeric usage at all (legacy payloads) remain a no-op.
  • Covered by updated UsageStoreCoverageTests cases: text→bar transition, clear-restores-text-only, no-numeric-usage no-op, and baseline-only sync.

make check clean; full make test green except the pre-existing locale-sensitive MiniMax billing assertion on main (unrelated files).

After-fix live proof from this head (text→bar transition on my Business seat) is next — will post the screenshot and update the PR body, then request re-review.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copilot Business (token-based billing): surface GitHub AI credit usage — card is blank because every quota reports unlimited/zero-entitlement

2 participants